package hyung.jin.seo.util;


import hyung.jin.seo.model.NumberBasket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Random;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
// util..util...
/**
 * @author jseo2510
 *
 */
public class Utility {

	/**
	 * This class is designed Singleton Pattern and
	 * used with SingletonHolder for safer thread-handling
	 */
	private Utility(){}

	public static Utility getInstance()
	{
		return SingletonHolder.instance;
	}
	
	private static class SingletonHolder
	{
		static final Utility instance = new Utility();
	}

	/**
	 * This method returns randomised number and supplement
	 * @param basket
	 * @return
	 */
	public NumberBasket randomiseNumber(NumberBasket basket)
	{
		String[] supplResult = generateSuppl(basket);
		NumberBasket result = generateNums(basket, (String)supplResult[0]);
		
		String[] nums = result.getNumbers();
		boolean[] choice = result.getSelected();
		String[] finalNums = new String[Constants.NUMBER_BALL+1];
		boolean[] finalChoice = new boolean[Constants.NUMBER_BALL+1];
		System.arraycopy(nums, 0, finalNums, 0, nums.length);
		finalNums[Constants.NUMBER_BALL] = (String) supplResult[0];
		System.arraycopy(choice, 0, finalChoice, 0, choice.length);
		finalChoice[Constants.NUMBER_BALL] = Boolean.parseBoolean((String)supplResult[1]);
		result.setNumbers(finalNums);
		result.setSelected(finalChoice);
		return result;
	}

	/**
	 * This method generates randomised number for supplement if not exits. Otherwise it returns user's choice as it was
	 * @param number
	 * @return
	 */
	private String[] generateSuppl(NumberBasket basket)
	{
		String number = basket.getNumbers()[Constants.NUMBER_BALL];
		String[] result = new String[2];
		String value = "0";
		String choice = "false";
		if((number!=null)&&(!number.equals(Constants.EMPTY_NUMBER)))
		{
			value = number.trim();
			choice = "true";
		}else{
			// check any user numbers come.
			// if exists, it will have to avoid duplicated supplement with numbers
			// therefore we should keep the values if they come
			String[] comein = basket.getNumbers();
			int[] exNum = new int[Constants.NUMBER_BALL];
			for(int i=0; i<Constants.NUMBER_BALL; i++)
			{
				if((comein[i]!=null)&&(!comein[i].equals(Constants.EMPTY_NUMBER)))
				{
					exNum[i] = Integer.parseInt(comein[i].trim());
				}
			}
			// randomise number
			int supplement = 0;
			do
			{
				supplement = new Random().nextInt(Constants.BALL_MAX_NUM)+1;
			}while(isContained(exNum, supplement));
			value = Integer.toString(supplement);
		}
		result[0] = value;
		result[1] = choice;
		return result;
	}
	/**
	 * This method generates randomised numbers excluding user defined numbers.
	 * It will be eventually put together with generateSuppl() to client. 
	 * @param basket
	 * @return
	 */
	private NumberBasket generateNums(NumberBasket basket, String suppl) 
	{
		int iterCnt = 0;
		String[] comein = new String[Constants.NUMBER_BALL];
		System.arraycopy(basket.getNumbers(), 0, comein, 0, comein.length);
		int[] tempRepo = new int[Constants.NUMBER_BALL];
		// check how many selected numbers come from user and keep them into temp[]
		for(int i=0; i<Constants.NUMBER_BALL; i++)
		{
			if((comein[i]!=null)&&(!comein[i].equals(Constants.EMPTY_NUMBER)))
			{
				tempRepo[iterCnt] = Integer.parseInt(comein[i].trim());
				iterCnt++;
			}
		}
		// generated number should not be identical to supplement
		int supplement = Integer.parseInt(suppl.trim());
		TreeSet<Integer> ts = new TreeSet<Integer>();
		Random num = new Random();
		int generated=0;
		int count=iterCnt;
		do
		{
			generated = num.nextInt(Constants.BALL_MAX_NUM)+1;
			// check if user already selects the same number or avoid same number with supplement 
			if(isContained(tempRepo, generated) || (generated==supplement))
			{
				continue;
			}
			if(ts.add(new Integer(generated)))
			{
				count++;
			}
		}while((count<Constants.NUMBER_BALL));
		
		// if there is any user defined number, add it into TreeSet for automatic sorting
		for(int j=0; j<Constants.NUMBER_BALL; j++)
		{
			if((comein[j]!=null)&&(!comein[j].equals(Constants.EMPTY_NUMBER)))
			{
				ts.add(new Integer(comein[j].trim()));
			}
		}
		return getNumbers(ts, basket);
	}
	
	private boolean isContained(int[] tempRepo, int generated)
	{
		for(int i=0; i<Constants.NUMBER_BALL; i++)
		{
			if(tempRepo[i]==generated)
			{
				return true;
			}
		}
		return false;
	}

	private NumberBasket getNumbers(Set<Integer> set, NumberBasket basket)
	{
		if(set==null)
		{
			return new NumberBasket(new String[]{"0","0","0","0","0","0"}, new boolean[]{false, false, false, false, false, false});
		}
		String[] tempNum = basket.getNumbers();
		Object[] integer = (Object[]) set.toArray();
		String[] selectedNum = new String[Constants.NUMBER_BALL];
		for(int i=0; i<Constants.NUMBER_BALL; i++)
		{
			selectedNum[i] = integer[i].toString();
		}
		// check index of temp[] element so as to put boolean[] value into basket
		boolean[] choice = new boolean[Constants.NUMBER_BALL];
		first:for(int j=0; j<Constants.NUMBER_BALL; j++)
		{
			if((tempNum[j]!=null)&&(!tempNum[j].equals(Constants.EMPTY_NUMBER))) // if number is there
			{
				// find index of number in result
				second:for(int k=0; k<Constants.NUMBER_BALL; k++)
				{
					if(selectedNum[k].trim().equals(tempNum[j].trim()))
					{
						// set true into boolean value in basket
						choice[k] = true;
						break second;
					}
				}
			}
		}
		basket.setNumbers(selectedNum);
		basket.setSelected(choice);
		return basket;
	}
	
	public String getResponseFromWeb(String address)
	{
		String result="";
		URL url = null;
		BufferedReader in = null;
		String str = null;

		try {
			url = new URL(address);
			in = new BufferedReader(new InputStreamReader(url.openStream()));
			while((str=in.readLine())!= null)
			{
				result += str + "\n";
			}
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return result.trim();
	}
	
	public String padding(String num)
	{
		if(num.length()==1)
		{
			return " "+num;
		}else{
			return num;
		}
	}
	
	public String putQueryString(String[] nums)
	{
		String query = "";
		for(int i=0; i<Constants.NUMBER_BALL+1; i++)
		{
			if(nums[i]==null)
			{
				nums[i] = "";
			}
			query += nums[i].trim()+"|";
		}
		query = query.substring(0, query.lastIndexOf("|"));
		return query.trim();
	}
	
	public String[] getQueryString(String array)
	{
		String[] nums = new String[Constants.NUMBER_BALL+1];
		StringTokenizer st = new StringTokenizer(array, "|");
		int cnt = 0;
		while(st.hasMoreTokens())
		{
			nums[cnt] = st.nextToken().trim();
			cnt++;
		}
		return nums;
	}
	
}
